#include "./container.h"
#include "ui/winview.h"
#include <windows.h>

using namespace MiniUI;
using namespace MiniUI::Type;

Container::Container(void)
: m_pWinView(nullptr)
, m_pObjFocus(nullptr)
, m_pObjMouseDown(nullptr)
, m_uLastClickTime(0)
, m_uLastClickTimes(0)
, m_ptLastClickPos(0, 0)
, m_uLastButton(MB_NONE)
{
    m_pBitmap = Bitmap::CreateInstance();
}

Container::~Container(void)
{
    if (m_pWinView)
    {
        m_pWinView->Release();
    }
    m_pBitmap->Release();
}

bool Container::Bind(WinView* pWinView)
{
    if (m_pWinView != pWinView)
    {
        if (m_pWinView)
        {
            UnlistenViewEvent();
            m_pWinView->Release();
            m_pWinView = nullptr;
        }
        m_pWinView = pWinView;
        if (pWinView)
        {
            pWinView->AddRef();
            ListenViewEvent();
            SyncRect();
        }
        return true;
    }
    return false;
}

void Container::ListenViewEvent()
{
    if (m_pWinView)
    {
        m_pWinView->OnChange += EventObject<OnChangeEventFunc>(this, &Container::ViewChange);
    }
}

void Container::UnlistenViewEvent()
{
    if (m_pWinView)
    {
        m_pWinView->OnChange -= EventObject<OnChangeEventFunc>(this, &Container::ViewChange);
    }
}

void Container::ViewChange(const UIObject* sender, const MiniRect& rect)
{
    Update(rect);
}

void Container::DoClick(const MiniPoint& pt, MouseButton button, uint keyState, bool& bHandled)
{
    if (m_pWinView)
    {
        UIObject* pObj = m_pWinView->DoHitTest(pt);
        if (pObj && (pObj == m_pObjMouseDown))
        {
            m_pObjMouseDown = nullptr;

            uint32 uLastClickTime = m_uLastClickTime;
            m_uLastClickTime = ::GetTickCount();
            if (m_uLastClickTime - uLastClickTime < ::GetDoubleClickTime() 
                && m_ptLastClickPos == pt && m_uLastButton == button)
                m_uLastClickTimes++;
            else
                m_uLastClickTimes = 1;
            m_uLastButton = button;
            m_ptLastClickPos = pt;
            m_pWinView->DoClick(pt, button, keyState, bHandled);
            if (m_uLastClickTimes > 1)
            {
                m_uLastClickTimes = 0;
                m_pWinView->DoDblClk(pt, button, keyState, bHandled);
            }
        }
        else
        {
            m_uLastClickTime = 0;
            m_uLastClickTimes = 0;
            m_ptLastClickPos.SetPoint(0, 0);
        }
        m_pObjMouseDown = nullptr;
    }
}

void Container::DoMouseDown(const MiniPoint& pt, MouseButton button, uint keyState, bool& bHandled)
{
    if (m_pWinView)
    {
        m_pObjMouseDown = m_pWinView->DoHitTest(pt);
        m_pWinView->DoMouseDown(pt, button, keyState, bHandled);
    }
}

void Container::DoMouseUp(const MiniPoint& pt, MouseButton button, uint keyState, bool& bHandled)
{
    if (m_pWinView)
    {
        m_pWinView->DoMouseUp(pt, button, keyState, bHandled);
    }
}

void Container::DoMouseMove(const MiniPoint& pt, uint keyState, bool& bHandled)
{
    if (m_pWinView)
    {
        if (m_pObjMouseDown)
        {
            MiniPoint relativePos = pt;
            MiniRect rect;
            m_pObjMouseDown->GetClientRect(rect);
            relativePos.Offset(-rect.TopLeft());

            m_pObjMouseDown->DoMouseMove(relativePos, keyState, bHandled);
        }
        else
        {
            m_pWinView->DoMouseMove(pt, keyState, bHandled);
        }
    }
}

void Container::DoMouseEnter()
{
    if (m_pWinView)
    {
        m_pWinView->DoMouseEnter();
    }
}

void Container::DoMouseLeave()
{
    if (m_pWinView)
    {
        m_pWinView->DoMouseLeave();
    }
}

void Container::DoMouseWheel(const MiniPoint& pt, uint keyState, int16 zDelta, bool& bHandled)
{
    if (m_pWinView)
    {
        MiniPoint ptView;
        m_pWinView->GetPos(ptView);
        ptView = ptView + pt;
        if (m_pWinView->HitTest(ptView))
        {
            m_pWinView->DoMouseWheel(pt, keyState, zDelta, bHandled);
        }
        if (bHandled == false)
        {
            //focus object
            UIObject* pObj = m_pWinView->GetFocusObject();
            if (pObj && pObj->CheckEnable() && pObj->CheckVisible())
            {
                MiniRect rcClient;
                pObj->GetClientRect(rcClient);
                MiniPoint ptFocus = pt;
                ptFocus.Offset(-rcClient.TopLeft());
                pObj->DoMouseWheel(ptFocus, keyState, zDelta, bHandled);
            }
        }
    }
}

void Container::DoActivate(bool bActivate)
{
    if (m_pWinView)
    {
        if (bActivate)
        {
            m_pWinView->SetFocusObject(m_pObjFocus);
            m_pObjFocus = nullptr;
        }
        else
        {
            m_pObjFocus = m_pWinView->GetFocusObject();
            m_pWinView->SetFocusObject(nullptr);
        }
    }
}

void Container::DoClose()
{
    //m_pWinView->DoClose();
}